using System;
using System.Diagnostics;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using com.bodurov.SilverlightControls.XmlCodeEditor.Extensions;

namespace com.bodurov.SilverlightControls.XmlCodeEditor.Tests
{
    [TestClass]
    public class StringExtensionsWorkAsExpected
    {
        [TestMethod]
        public void Can_Split_String_And_Retain_Delimiters_Case_1()
        {
            const string s = "attrs: <a href=\"abc\\\"def'g\" rel='1\"2\\\''>";

            var parts = s.SplitAndRetainDelimiter(new[] {'\"', '\''});

            var i = 0;
            Assert.AreEqual("attrs: <a href=", parts[i++]);
            Assert.AreEqual("\"", parts[i++]);
            Assert.AreEqual("abc\\", parts[i++]);
            Assert.AreEqual("\"", parts[i++]);
            Assert.AreEqual("def", parts[i++]);
            Assert.AreEqual("'", parts[i++]);
            Assert.AreEqual("g", parts[i++]);
            Assert.AreEqual("\"", parts[i++]);
            Assert.AreEqual(" rel=", parts[i++]);
            Assert.AreEqual("'", parts[i++]);
            Assert.AreEqual("1", parts[i++]);
            Assert.AreEqual("\"", parts[i++]);
            Assert.AreEqual("2\\", parts[i++]);
            Assert.AreEqual("'", parts[i++]);
            Assert.AreEqual("", parts[i++]);
            Assert.AreEqual("'", parts[i++]);
            Assert.AreEqual(">", parts[i++]);

            Assert.AreEqual(i, parts.Length);
        }

        [TestMethod]
        public void Can_Split_String_And_Retain_Delimiters_If_No_Delimiter_Is_Found()
        {
            const string s = "attrs: <a href=\"abc\\\"def'g\" rel='1\"2\\\''>";

            var parts = s.SplitAndRetainDelimiter(new[] { '@', '#' });

            Assert.AreEqual(1, parts.Length);

            Assert.AreEqual(s, parts[0]);
        }

        [TestMethod]
        public void Can_Split_String_And_Retain_Delimiters_For_Empty_String()
        {
            const string s = "";

            var parts = s.SplitAndRetainDelimiter(new[] { '@', '#' });

            Assert.AreEqual(1, parts.Length);

            Assert.AreEqual(s, parts[0]);
        }

        [TestMethod]
        public void Will_Not_Allow_To_Split_String_And_Retain_Delimiters_For_Less_Than_Zero_Parts_Requested()
        {
            const string s = "abc@def";
            try
            {
                var parts = s.SplitAndRetainDelimiter(new[] {'@', '#'}, -1);
            }catch(ArgumentException)
            {
                return;
            }
            Assert.Fail("Expected exception was not thrown");
        }
        [TestMethod]
        public void Will_Not_Allow_To_Split_String_And_Retain_Delimiters_For_Zero_Parts_Requested()
        {
            const string s = "abc@def";
            try
            {
                var parts = s.SplitAndRetainDelimiter(new[] { '@', '#' }, 0);
            }
            catch (ArgumentException)
            {
                return;
            }
            Assert.Fail("Expected exception was not thrown");
        }
        [TestMethod]
        public void Will_Not_Allow_To_Split_String_And_Retain_Delimiters_For_One_Part_Requested()
        {
            const string s = "abc@def";
            try
            {
                var parts = s.SplitAndRetainDelimiter(new[] { '@', '#' }, 1);
            }catch(ArgumentException)
            {
                return;
            }
            Assert.Fail("Expected exception was not thrown");
        }

        [TestMethod]
        public void Can_Split_String_And_Retain_Delimiters_For_Two_Parts_Requested()
        {
            const string s = "abc@def#g\nh";
            var parts = s.SplitAndRetainDelimiter(new[] { '@', '#' }, 2);
            Assert.AreEqual(3, parts.Length);
            Assert.AreEqual("abc", parts[0]);
            Assert.AreEqual("@", parts[1]);//delimiter
            Assert.AreEqual("def#g\nh", parts[2]);
        }

        [TestMethod]
        public void Can_Split_String_And_Retain_Delimiters_For_Three_Parts_Requested()
        {
            const string s = "abc@def#g\nh";
            var parts = s.SplitAndRetainDelimiter(new[] { '@', '#' }, 3);
            Assert.AreEqual(5, parts.Length);
            Assert.AreEqual("abc", parts[0]);
            Assert.AreEqual("@", parts[1]);//delimiter
            Assert.AreEqual("def", parts[2]);
            Assert.AreEqual("#", parts[3]);
            Assert.AreEqual("g\nh", parts[4]);
        }

        [TestMethod]
        public void Can_Split_String_And_Retain_Delimiters_For_Less_Than_Requested()
        {
            const string s = "abc@def#g\nh";
            var parts = s.SplitAndRetainDelimiter(new[] { '@', '#' }, 7);
            Assert.AreEqual(5, parts.Length);
            Assert.AreEqual("abc", parts[0]);
            Assert.AreEqual("@", parts[1]);//delimiter
            Assert.AreEqual("def", parts[2]);
            Assert.AreEqual("#", parts[3]);
            Assert.AreEqual("g\nh", parts[4]);
        }


        [TestMethod]
        public void Can_Set_Max_Array_Elements_Number()
        {
            var array = new[] {"aaa", "bbb", "ccc", "ddd", "eee"};

            array = array.SetMaxElements(3);

            Assert.AreEqual(3, array.Length);
            Assert.AreEqual("aaa", array[0]);
            Assert.AreEqual("bbb", array[1]);
            Assert.AreEqual("cccdddeee", array[2]);
        }

        [TestMethod]
        public void Can_Set_Redundant_Max_Array_Elements_Number_1()
        {
            var array = new[] { "aaa", "bbb", "ccc"};

            array = array.SetMaxElements(3);

            Assert.AreEqual(3, array.Length);
            Assert.AreEqual("aaa", array[0]);
            Assert.AreEqual("bbb", array[1]);
            Assert.AreEqual("ccc", array[2]);
        }

        [TestMethod]
        public void Can_Set_Redundant_Max_Array_Elements_Number_2()
        {
            var array = new[] { "aaa", "bbb", "ccc" };

            array = array.SetMaxElements(4);

            Assert.AreEqual(3, array.Length);
            Assert.AreEqual("aaa", array[0]);
            Assert.AreEqual("bbb", array[1]);
            Assert.AreEqual("ccc", array[2]);
        }

        [TestMethod]
        public void Will_Not_Allow_To_Set_Max_Array_Elements_Number_Zero()
        {
            var array = new[] { "aaa", "bbb", "ccc" };
            try
            {
                array = array.SetMaxElements(0);
            }
            catch (ArgumentException)
            {
                return;
            }
            Assert.Fail("Expected exception was not thrown");
        }

        [TestMethod]
        public void Will_Not_Allow_To_Set_Max_Array_Elements_Number_Less_Than_Zero()
        {
            var array = new[] { "aaa", "bbb", "ccc" };
            try
            {
                array = array.SetMaxElements(-10);
            }
            catch (ArgumentException)
            {
                return;
            }
            Assert.Fail("Expected exception was not thrown");
        }


        [TestMethod]
        public void Can_Split_Quoted_Strings_Case_SingleChar()
        {
            const string s = "{";
            var parts = s.SplitQuotedStrings();

            Debug.WriteLine(parts.Length);
        }

        [TestMethod]
        public void Can_Split_Quoted_Strings_Case_1()
        {
            const string s = "aaa\"bbb\"";
            var parts = s.SplitQuotedStrings();

            Assert.AreEqual(2, parts.Length);
            Assert.AreEqual(parts[0], "aaa");
            Assert.AreEqual(parts[1], "\"bbb\"");
        }

        [TestMethod]
        public void Can_Split_Quoted_Strings_Case_2()
        {
            const string s = "aaa\"bbb\\\"ccc'ddd\" eee='fff\"ggg\\'hhh'";
            var parts = s.SplitQuotedStrings();

            Assert.AreEqual(4, parts.Length);
            Assert.AreEqual(parts[0], "aaa");
            Assert.AreEqual(parts[1], "\"bbb\\\"ccc'ddd\"");
            Assert.AreEqual(parts[2], " eee=");
            Assert.AreEqual(parts[3], "'fff\"ggg\\'hhh'");
        }

        [TestMethod]
        public void Can_Split_Quoted_Strings_If_No_Delimiter()
        {
            const string s = "aaa bbb ccc";
            var parts = s.SplitQuotedStrings();

            Assert.AreEqual(1, parts.Length);
            Assert.AreEqual(parts[0], s);
        }

        [TestMethod]
        public void Can_Split_Quoted_Strings_If_No_Delimiter_In_Empty()
        {
            const string s = "";
            var parts = s.SplitQuotedStrings();

            Assert.AreEqual(1, parts.Length);
            Assert.AreEqual(parts[0], s);
        }
    }
}